using System;
using System.Collections;
using System.ComponentModel.Design;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Linq;
using BlazorApp4.Data;
using Dapr.Client;
using Dapr.Client.Autogen.Grpc.v1;
using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Client;

namespace BlazorApp4
{
    public class BlazorChatHub : Hub
    {
        public const string HubUrl = "/chat";

        public static Dictionary<String, String> UserConnectionMap = new Dictionary<string, string>();

        const string DAPR_STATE_STORE = "statestore";

        private DaprClient daprClient;

        public BlazorChatHub(DaprClient _daprClient)
        {
            daprClient = _daprClient;
        }
        //这里的username是发起者
        public async Task Broadcast(string username, string message)
        {
             Console.WriteLine("result is " + username);
            if (message.Contains("离开聊天室")) {
                UserConnectionMap.Remove(username);
            } else {
                if (UserConnectionMap.ContainsKey(username)) {
                    UserConnectionMap.Remove(username);
                }
                UserConnectionMap.Add(username, Context.ConnectionId);
                Console.WriteLine("result is " + UserConnectionMap[username]);
            }
            await Clients.All.SendAsync("Broadcast", username, message);

        }

        public async Task SendFile(Stream fileStream)
        {
            Console.WriteLine($"SendFile");
            await Clients.All.SendAsync("ReceiveFile", fileStream);
        }

        public async Task UploadFile2Spec(string username, string toSpec, string fileName, byte[] byteArray)
        {
            Console.WriteLine($"UploadFile");
            MemoryStream stream = new MemoryStream(byteArray);
            var message = String.Empty;
            var extension = Path.GetExtension(fileName);
            string specPath = username + "2" + toSpec;
            if (extension == ".jpg" || extension == ".png" || extension == ".jpeg" || extension == ".gif")
            {
                var path = Path.Combine("wwwroot", "files", "img", specPath);
                if(!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                path = Path.Combine("wwwroot", "files", "img", specPath, fileName);

                using (var fileStream = new FileStream(path, FileMode.Create))
                {
                    await stream.CopyToAsync(fileStream);
                }
                message = "wwwroot/files/img/" + specPath + "/" + fileName + "@" + username;
            }
            else
            {
                var path = Path.Combine("wwwroot", "files", "file", specPath);
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }

                path = Path.Combine("wwwroot", "files", "file", specPath, fileName);
                using (var fileStream = new FileStream(path, FileMode.Create))
                {
                    await stream.CopyToAsync(fileStream);
                }
                message = "wwwroot/files/file/" + specPath +"/" + fileName + "@" + username;
            }

            await Clients.Client(UserConnectionMap[username]).SendAsync("BroadcastSelf", username, message.Replace("@" +username, ""), toSpec);
            await BroadcastToSpecificUser(toSpec, message);
        }

        //文件上传
        public async Task UploadFile(string username, string fileName, byte[] byteArray)
        {
            Console.WriteLine($"UploadFile");
            MemoryStream stream = new MemoryStream(byteArray);
            // var buffer = new byte[81920];
            // var totalBytesRead = 0L;
            // var fileSize = stream.Length;

            // while (true)
            // {
            //     var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);

            //     if (bytesRead == 0)
            //     {
            //         break;
            //     }

            //     totalBytesRead += bytesRead;

            //     var progress = (double)totalBytesRead / fileSize;

            //     await Clients.Caller.SendAsync("ReceiveProgress", progress);

            //     await Task.Delay(100);
            // }

            // await Clients.Caller.SendAsync("ReceiveProgress", 1.0);
            // await Clients.All.SendAsync("ReceiveFile", byteArray);

            var message = String.Empty;
            var extension = Path.GetExtension(fileName);
            if (extension == ".jpg" || extension == ".png" || extension == ".jpeg" || extension == ".gif")
            {
                using (var fileStream = new FileStream(Path.Combine("wwwroot", "files", "img", fileName), FileMode.Create))
                {
                    await stream.CopyToAsync(fileStream);
                }
                message = "wwwroot/files/img/" + fileName + "@" + username;
            } else {
                using (var fileStream = new FileStream(Path.Combine("wwwroot", "files", "file", fileName), FileMode.Create))
                {
                    await stream.CopyToAsync(fileStream);
                } 
                message = "wwwroot/files/file/" + fileName + "@" + username;
            }
            await Clients.All.SendAsync("Broadcast", username, message);
        }

        public async Task UploadImg(string fileName, string base64)
        {
            Console.WriteLine(base64 + fileName);
            Console.WriteLine($"UploadImg");
            await Clients.All.SendAsync("ReceiveImg", base64);
        }



        public async Task SendStream(byte[] byteArray)
        {
            MemoryStream stream = new MemoryStream(byteArray);
            Console.WriteLine("when to invoke SendStream");
            using (var fileStream = new FileStream(Path.Combine("wwwroot", "files", "img", "stream.txt"), FileMode.Create))
            {
                await stream.CopyToAsync(fileStream);
            }
        }

        //这里的user是目标用户
        public async Task BroadcastToSpecificUser(string username, string message)
        {
            Console.WriteLine("when to invoke:" + username);
            foreach (var key in UserConnectionMap){
                Console.WriteLine("when to invok map:" + key);
            }
			String connectionId = String.Empty;
			if (UserConnectionMap.ContainsKey(username)) {
				connectionId = UserConnectionMap[username];
			}
		    string[] split_arr = message.Split("@");
            string from_user = split_arr[split_arr.Length - 1];
			var restore_message = "";
			for (var i = 0; i < split_arr.Length - 1; i++)
			{
			    restore_message += split_arr[i];
			}
			// 如何判断connection是否有效
            if (connectionId == String.Empty){
                List<RecentUser> _recentUsers = await daprClient.GetStateAsync<List<RecentUser>>(DAPR_STATE_STORE, username + "_recent_users");
				if (_recentUsers == null) {
					Console.WriteLine("当前用户已经失效");
                    _recentUsers =  new List<RecentUser>();

				}
                var result = _recentUsers.Find(recentUser => recentUser.Username == from_user);
                if (result == null)
				{
				    Console.WriteLine("is come to here");
                    if (from_user != null)
                    {
                        var recentUser = new RecentUser(from_user, 1, restore_message);
                        _recentUsers.Add(recentUser);
                    }
				}
				else
				{
                    foreach (var recentUser in _recentUsers)
                    {
                        if ((recentUser.Username == from_user))
                        {
                            recentUser.Counter = recentUser.Counter + 1;
							recentUser.LatestMessage = restore_message;
                            Console.WriteLine(" BroadcastToSpecificUser badge数量:" + recentUser.Counter);
                        }
                    }
                    Console.WriteLine("is come to here contain");
				}
                await daprClient.SaveStateAsync(DAPR_STATE_STORE, username + "_recent_users", _recentUsers);
                List<Message> _specoficMessages =  await daprClient.GetStateAsync<List<Message>>(DAPR_STATE_STORE, username + "_spec_" + from_user);
				if (_specoficMessages == null) {
				    _specoficMessages = new List<Message>();
				}
				//根据_hubConnection.On<string, string>("Broadcast", BroadcastMessage);有相应的name
				var specific_message = new Message(from_user, restore_message, false);
				_specoficMessages.Add(specific_message);
				//当前用户和来源用户作为键
				await daprClient.SaveStateAsync(DAPR_STATE_STORE, username + "_spec_" + from_user, _specoficMessages);
				return;
            }
            await daprClient.SaveStateAsync(DAPR_STATE_STORE, from_user + "_to_" + username, true);
            Console.WriteLine("Broadcast:" + connectionId);
            await Clients.Client(connectionId).SendAsync("Broadcast", username, message);
            Console.WriteLine("Broadcast finish:" + connectionId);
        }

        public override Task OnConnectedAsync()
        {
            Console.WriteLine($"{Context.ConnectionId} connected");
            return base.OnConnectedAsync();
        }

        public override async Task OnDisconnectedAsync(Exception e)
        {
            Console.WriteLine($"Disconnected {e?.Message} {Context.ConnectionId}");
            await base.OnDisconnectedAsync(e);
        }
    }
}